/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.raflik.queryxml.serializer.standard;

import java.io.OutputStream;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.openide.util.NbBundle;
import org.openide.xml.XMLUtil;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import pl.raflik.queryxml.serializer.QueryResultSerializeException;

/**
 *
 * @author raflik
 */
public class XMLTransformer extends AbstractTransformer {

    private static final String RESULT_ROOT_DEFAULT = "queryResult";
    private static final String RESULT_ROOT_PREF_KEY = "RESULT_ROOT_PREF_KEY";
    private static final boolean INDENT_DEFAULT = true;
    private static final String INDENT_PREF_KEY = "INDENT_PREF_KEY";
    private static final boolean OMIT_XML_DECLARATION_DEFAULT = false;
    private static final String OMIT_XML_DECLARATION_PREF_KEY = "OMIT_XML_DECLARATION_PREF_KEY";

    public static String getXMLResultRoot() {
        String userValue = PrefUtil.getStringSetting(XMLTransformer.class, RESULT_ROOT_PREF_KEY, RESULT_ROOT_DEFAULT);
        if (userValue == null || userValue.equals("")) {
            return RESULT_ROOT_DEFAULT;
        }
        return userValue;
    }

    public static void setXMLResultRoot(String value) {
        PrefUtil.setStringSetting(XMLTransformer.class, RESULT_ROOT_PREF_KEY, value);
    }

    public static boolean getIndent() {
        return PrefUtil.getBooleanSetting(XMLTransformer.class, INDENT_PREF_KEY, INDENT_DEFAULT);
    }

    public static void setIndent(boolean value) {
        PrefUtil.setBooleanSetting(XMLTransformer.class, INDENT_PREF_KEY, value);
    }

    public static boolean getOmitXmlDeclaration() {
        return PrefUtil.getBooleanSetting(XMLTransformer.class, OMIT_XML_DECLARATION_PREF_KEY, OMIT_XML_DECLARATION_DEFAULT);
    }

    public static void setOmitXmlDeclaration(boolean value) {
        PrefUtil.setBooleanSetting(XMLTransformer.class, OMIT_XML_DECLARATION_PREF_KEY, value);
    }

    private static Document wrapDataInXML(List<?> list) throws ParserConfigurationException {
        final String root = getXMLResultRoot();
        final Document xmlDoc = XMLUtil.createDocument(root, null, null, null);
        //xmlDoc.appendChild(xmlDoc.createElement(XML_RESULT_ROOT_NAME));

        final Element xmlRoot = xmlDoc.getDocumentElement();

        for (Object listEl : list) {
            if (listEl instanceof Node) {
                Node xmlNode = (Node) listEl;
                if (xmlNode instanceof Document) {
                    xmlNode = ((Document) xmlNode).getDocumentElement();
                }
                final Node importedNode = xmlDoc.importNode(xmlNode, true);
                if (importedNode instanceof Attr) {
                    Attr importedAttr = (Attr) importedNode;
                    xmlRoot.setAttributeNode(importedAttr);
                } else {
                    xmlRoot.appendChild(importedNode);
                }
            }
            if (listEl instanceof String || listEl instanceof Number || listEl instanceof Boolean) {
                Element primitiveEl = xmlDoc.createElement(listEl.getClass().getCanonicalName());
                primitiveEl.setTextContent(listEl.toString());
                xmlRoot.appendChild(primitiveEl);
            }
        }
        return xmlDoc;
    }

    public void serialize(List<?> queryResult, OutputStream os, Object param) throws QueryResultSerializeException {
        checkSerializeInvocation(queryResult, os, param);

        try {
            Document xmlDoc = null;
            xmlDoc = wrapDataInXML(queryResult);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer serializer = tf.newTransformer();
            DOMSource domSource = new DOMSource(xmlDoc);
            StreamResult streamResult = new StreamResult(os);
            serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            boolean indent = getIndent();
            serializer.setOutputProperty(OutputKeys.INDENT, bool2yesno(indent));
            boolean omitXmlDeclaration = getOmitXmlDeclaration();
            serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, bool2yesno(omitXmlDeclaration));

            serializer.transform(domSource, streamResult);
        } catch (Exception e) {
            throw new QueryResultSerializeException(e);
        }
    }

    private String bool2yesno(boolean bool) {
        return bool ? "YES" : "NO"; //NOI18N
    }
    private static Object[] params = new Object[0];

    public Object[] getParams() {
        return params;
    }

    public String getExtension() {
        return "xml"; //NOI18
    }

    public String supportedOutputType() {
        return NbBundle.getMessage(XMLTransformer.class, "XMLTransformer.supportedOutputType");
    }
}
